﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Kinect.CursorMove;
using Microsoft.Research.Kinect.Nui;

namespace Kinect.Viewer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private Runtime _nui;
        private bool _isInit;
        private byte[] _convertedDepthFrame;

        private KinectCursor _cursor;

        private BitmapSource _depthBitmapSource;
        public BitmapSource DepthBitmapSource
        {
            get { return _depthBitmapSource; }
            private set
            {
                _depthBitmapSource = value;
                OnPropertyChanged("DepthBitmapSource");
            }
        }

        private SensorTools _sensorTools;

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        ~MainWindow()
        {
            if (_isInit)
                _nui.Uninitialize();
        }

        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            try
            {
                foreach (Runtime kinect in Runtime.Kinects)
                {
                    if (kinect.Status == KinectStatus.Connected)
                    {
                        _nui = kinect;
                        break;
                    }
                }
                if (Runtime.Kinects.Count == 0)
                    MessageBox.Show("No Kinect found", "KinectViewer", MessageBoxButton.OK, MessageBoxImage.Error);
                else
                    StartInit();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "KinectViewer", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
        }

        private void StartInit()
        {
            if (_nui == null)
                return;

            try
            {
                _nui.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking);
                _isInit = true;
                _nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "KinectViewer", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            _nui.DepthFrameReady += NuiDepthFrameReady;
            _nui.SkeletonFrameReady += NuiSkeletonFrameReady;
            _nui.SkeletonEngine.TransformSmooth = true;
            var parameters = new TransformSmoothParameters
                                 {
                                     Smoothing = 1.0f,
                                     Correction = 0.1f,
                                     Prediction = 0.1f,
                                     JitterRadius = 0.05f,
                                     MaxDeviationRadius = 0.05f
                                 };
            _nui.SkeletonEngine.SmoothParameters = parameters;
            _sensorTools = new SensorTools();
            _cursor = new KinectCursor(KinectCursor.CursorPrecision.Normal, 0.9f, 1680, 1050);

        }

        private void NuiDepthFrameReady(object sender, ImageFrameReadyEventArgs e)
        {
            PlanarImage image = e.ImageFrame.Image;

            _convertedDepthFrame = _sensorTools.ConvertDepthFrame(image.Bits);
            DepthBitmapSource = BitmapSource.Create(image.Width, image.Height, 96, 96, PixelFormats.Bgr32, null,
                                                       _convertedDepthFrame, image.Width*4);
        }

        private void NuiSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            SkeletonFrame allSkeletons = e.SkeletonFrame;
		    SkeletonData skeleton = allSkeletons.Skeletons.FirstOrDefault(s => s.TrackingState == SkeletonTrackingState.Tracked);
            if (skeleton != null)
            {
                _cursor.StartCursor(skeleton, JointID.HandRight);
            }
        }

        #region INotifyPropertyChanged

        /// <summary>
        /// Evénement déclenché lorsqu'un propriété change.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Déclenche l'événement <see cref="PropertyChanged"/>.
        /// </summary>
        /// <param name="propertyName">Le nom de la propriété.</param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}
